package com.shopnight.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shopnight.constant.ShopIndentConstant;
import com.shopnight.entity.Post;
import com.shopnight.entity.PostComment;
import com.shopnight.entity.User;
import com.shopnight.interceptors.JWTInterceptor;
import com.shopnight.mapper.PostCommentMapper;
import com.shopnight.mapper.UserMapper;
import com.shopnight.result.ApiResult;
import com.shopnight.service.PostService;
import com.shopnight.mapper.PostMapper;
import com.shopnight.utils.UserContext;
import com.shopnight.vo.MessageListVo;
import com.shopnight.vo.PostInfoVo;
import com.shopnight.vo.PostListVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
* @author 13201
* @description 针对表【post】的数据库操作Service实现
* @createDate 2023-05-08 23:45:34
*/
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService{

    @Autowired
    PostCommentMapper postCommentMapper;
    @Autowired
    PostMapper postMapper;
    @Autowired
    UserMapper userMapper;

    @Resource(name = "taskExecutor")
    Executor executor;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private String prefix = "mqtt-topic:";


    public Page<PostListVo> getPostList(Page page, Integer orgId, Integer categoryId) {
        Page<PostListVo> postList = postMapper.getPostList(page, orgId, categoryId);

        getPostComment(postList);

        return postList;
    }

    @Override
    public PostInfoVo getPostInfo(Integer id) {
        PostInfoVo postInfo = postMapper.getPostInfo(id);

        Post post = new Post();
        post.setId(postInfo.getId());
        post.setClickhitNum( postInfo.getClickhitNum() + 1 );

        //更新点击次数
        postMapper.updateById(post);

        return postInfo;
    }

    @Override
    public Integer addPost(Post post) {
        String userId =  UserContext.getEndUserId();
        post.setUserId(Integer.valueOf(userId));
        post.setCreateTime(new Date());
        post.setCheckStatus(ShopIndentConstant.PostCheckStatusEnum.unreviewed.getStatus());
        post.setClickhitNum(0);

        postMapper.insert(post);

        return post.getId();
      //更新redis缓存数据
      // stringRedisTemplate.opsForHash().put(prefix + userId , post.getId().toString(),""  );
    }

    @Override
    public Page<PostListVo> getPostListRecommend(Page page, Integer orgId, Integer categoryId) {
        Page<PostListVo> postList = postMapper.getPostList(page,orgId,categoryId);
        return null;
    }

    @Override
    public ApiResult delPost(Integer id) {
        String userId =  UserContext.getEndUserId();
        Post post = postMapper.selectById(id);

        if (! post.getUserId().toString().equals(userId) ){
            return ApiResult.fail("用户不匹配！");
        }


        //清空用户消息列表
       CompletableFuture.runAsync( ()->{
        Set<String> keys = stringRedisTemplate.keys("mqtt-topic*");
        if (keys != null) {
            for (String key : keys) {
                    String hashKey = "wall-post:" + post.getId();
                    if (stringRedisTemplate.opsForHash().hasKey(key, hashKey)) {
                        stringRedisTemplate.opsForHash().delete(key, hashKey);
                    }
            }
        }
        },executor);



        return  ApiResult.ok(postMapper.deleteById(id));
    }

    @Override
    public Page<PostListVo> getMyPost(Page page) {
        String userId =  UserContext.getEndUserId();

        Page<PostListVo> postList = postMapper.getMyPost(page,Integer.valueOf(userId));

        getPostComment(postList);

        return postList;

    }

    public List<MessageListVo> getMessageList() {
        String userId = UserContext.getEndUserId();
        // 从 Redis 中获取帖子 ID 集合

        Set<Object> keys = stringRedisTemplate.opsForHash().keys(prefix + userId);
        List<Integer> postIds = keys.stream()
                .filter(key-> key.toString().contains("wall-post"))
                .map(key-> {
                    String[] split = key.toString().split(":");
                    return Integer.valueOf( split[1] );
                })
                .collect(Collectors.toList());

        // 颠倒集合顺序
        Collections.reverse(postIds);
        if (postIds.isEmpty()) {
            return Collections.emptyList();
        }

        List<Post> posts = postMapper.selectBatchIds(postIds);
        if (posts.isEmpty() ) {
            return Collections.emptyList();
        }

        List<MessageListVo> res = new ArrayList<>(posts.size());

        posts.parallelStream().forEach(post->{

            MessageListVo messageListVo = new MessageListVo();
            messageListVo.setId(post.getId());
            messageListVo.setContent(post.getContent());
            messageListVo.setCreateDate(post.getCreateTime());
            User userById = userMapper.selectById(post.getUserId());
            messageListVo.setAvatar(userById.getAvatar());
            messageListVo.setUserId(userById.getUserId());
            messageListVo.setUnreadAmount(Integer.valueOf( stringRedisTemplate.opsForHash().get(prefix + userId,"wall-post:" + post.getId() ).toString() ));

            List<PostComment> postComments = postCommentMapper.selectList(new LambdaQueryWrapper<PostComment>()
                    .eq(PostComment::getPostId, post.getId())
                    .orderByDesc(PostComment::getCreateDate)
                    .last("limit 0, 9"));

            List<Integer> userIds;
            List<User> users;
            Map<Integer, User> userMap;

            if (postComments.size() > 0){
                userIds = postComments.stream().map(PostComment::getUserId).distinct().collect(Collectors.toList());
                users = userMapper.selectBatchIds(userIds);
                userMap = users.stream().collect(Collectors.toMap(user-> Integer.valueOf(user.getUserId().toString()), user -> user));
                List<MessageListVo.Comment> commentList = postComments.stream()
                        .map(comment -> {
                            MessageListVo.Comment messageComment = new MessageListVo.Comment();
                            BeanUtils.copyProperties(comment, messageComment);
                            User user = userMap.get(comment.getUserId());
                            if (user != null) {
                                BeanUtils.copyProperties(user, messageComment);
                            }
                            return messageComment;
                        })
                        .collect(Collectors.toList());
                messageListVo.setCommentList(commentList);

            }
            res.add(messageListVo);
        });
        if (res.size() > 0){
            Collections.sort(res,(MessageListVo a1, MessageListVo a2) -> {
                        return Long.compare(
                                getLastCommentCreateDate(a2).getTime(),
                                getLastCommentCreateDate(a1).getTime()
                                );
            });
        }

        return res;
    }

    // 获取最后一条评论的创建时间
    private Date getLastCommentCreateDate(MessageListVo messageListVo) {
        List<MessageListVo.Comment> commentList = messageListVo.getCommentList();
        if (commentList == null || commentList.isEmpty()) {
            return messageListVo.getCreateDate();
        } else {
            return commentList.get(commentList.size() - 1).getCreateDate();
        }
    }

    @Override
    public Page<PostListVo> getTheyPost(Integer userId, Page page) {
        Page<PostListVo> postList = postMapper.getMyPost(page,userId);

        getPostComment(postList);

        return postList;
    }


    public void getPostComment( Page<PostListVo> postList ){

        List<Integer> postIdList = postList.getRecords().stream().map(PostListVo::getId).collect(Collectors.toList());

        if(postIdList.size() > 0 ){

            Map<Integer, List<PostComment>> commentMap = postCommentMapper.selectList(
                    new LambdaQueryWrapper<PostComment>()
                            .in(PostComment::getPostId, postIdList)
                            .orderByDesc(PostComment::getCreateDate)
                    //.last("limit 8")
            ).stream().collect(Collectors.groupingBy(PostComment::getPostId));

            postList.getRecords().forEach(postVo -> {

                List<PostComment> postComments = commentMap.containsKey(postVo.getId()) ? commentMap.get(postVo.getId()) : new ArrayList<>() ;

                postVo.setHeat( postComments.size() * 10 + postVo.getClickhitNum() * 2 );

                if (postComments.size() > 0 ){
                    List<PostComment> postCommentsLimit = postComments.stream().collect(Collectors.collectingAndThen(
                                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PostComment::getUserId))),
                                    ArrayList::new))
                            .stream()
                            .collect(Collectors.collectingAndThen(Collectors.toList(),
                                    l -> l.size() > 8 ? l.stream().skip(l.size() - 8).limit(8).collect(Collectors.toList()) : l));;

                    if (postCommentsLimit != null && !postCommentsLimit.isEmpty()) {
                        List<PostListVo.PostCommentList> commentList = postCommentsLimit.parallelStream().map(postComment -> {
                            PostListVo.PostCommentList comment = new PostListVo.PostCommentList();
                            comment.setCreateDate(postComment.getCreateDate());
                            User user = userMapper.selectById(postComment.getUserId());
                            comment.setAvatar(user.getAvatar());
                            comment.setUserId(user.getUserId());
                            return comment;
                        }).collect(Collectors.toList());
                        Collections.reverse(commentList);

                        postVo.setPostCommentList(commentList);
                    }

                }

            });
        }

    }

}




